#ifndef SIXTEENJT_READER_H
#define SIXTEENJT_READER_H

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <pthread.h>
#include <algorithm>
#include <math.h>
#include <list>
#include <jni.h>

#include "Socket2.h"
#include "Protocol.h"

using namespace std;

struct CALLBACK_IDS {
    jmethodID on_alive;
    jmethodID on_inv;
    jmethodID on_inv_stop;
};

#define MAX_READ_LENGTH     2048
#define TIMEOUT             1000

/**
 * @brief 缓存返回值
 */
struct JT_RETURN {
    sem_t semaphore;
    unsigned char cmd;      /**<! 需要返回值的命令码 */
    unsigned char len;      /**<! 返回值的长度 */
    unsigned char data[MAX_READ_LENGTH];    /**<! 缓存返回值 */
};

struct JT_TRANS {
    unsigned int size;
    unsigned char data[MAX_READ_LENGTH];
    int head_count;
    int data_count;
    unsigned char cmd;
    unsigned short id;
    unsigned short payload_len;
    unsigned char payload[MAX_READ_LENGTH];
    unsigned char bcc;
};

class Reader {

public:
    Reader(void);

    ~Reader(void);

    bool connect(const char *ip, short port);

    bool disconnect();

    /**
     * @brief 盘点
     */
    int inventory(int times);

    /**
     * 点亮发光标签
     */
    int light(unsigned char *epc, unsigned char len);

    /**
     * 获取天线参数
     */
    int get_ant(JT_ANT_16 &ant);

    /**
     * 设置天线参数
     */
    int set_ant(JT_ANT_16 ant);

    int start_light_multi(std::list<SEL_MASK> marks, int times);

    int stop_light_multi();

    /**
     * 获取频率
     */
    int get_freq(JT_FRQ &freq);

    /**
     * 设置频率
     */
    int set_freq(JT_FRQ freq);

    JavaVM *jvm;
    jobject thiz;
    jclass cls_string;
    jstring ascii;

private:
    int inv_times;
    int inv_completed;
    bool inventorying;

    char ip[20];
    short port;

    JT_RETURN jt_ret;

    struct timespec sem_add_ms(int ms) {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        long secs = ms / 1000;
        ms = ms % 1000;

        long add = 0;
        long ns = ms * 1000 * 1000 + ts.tv_nsec;
        add = ns / (1000 * 1000 * 1000);
        ts.tv_sec += (add + secs);
        ts.tv_nsec = ns % (1000 * 1000 * 1000);
        return ts;
    }

    /**
     * c++字符串转java字符串
     */
    jstring std2j(JNIEnv *env, std::string str) {
        int l = str.length();
        jmethodID init = env->GetMethodID(cls_string, "<init>", "([BLjava/lang/String;)V");
        jbyteArray bytes = (env)->NewByteArray(l);
        env->SetByteArrayRegion(bytes, 0, l, (jbyte *) str.c_str());
        jstring res = reinterpret_cast<jstring> (env->NewObject(cls_string, init, bytes, ascii));
        env->DeleteLocalRef(bytes);
        return res;
    }

    /**
     * @brief 读取数据线程
     */
    pthread_t thread_read;
    bool read_thread_flag;

    static void *ReadThreadProc(void *args);

    JT_TRANS jt_trans;

    void translate(JNIEnv *env, CALLBACK_IDS ids);

    void command(JNIEnv *env, CALLBACK_IDS ids);

    std::list<SEL_MASK> marks;
    int light_times;

    pthread_t thread_light_multi;
    volatile bool flag_light_multi;

    static void *LightMultiProc(void *args);

    static void *LightMultiProc2(void *args);

    pthread_t thread_ant_inv;
    static void *SetAntAndInvProc(void *args);
    int high;
protected:
    Socket2 socket2;

    int write_cmd(unsigned char cmd, unsigned char *data, unsigned short len);

    int read_cmd(unsigned char cmd, unsigned int timeout = TIMEOUT);
};

#endif //SIXTEENJT_READER_H
